package com.leenmvc.core.dao.communal;

import com.leenmvc.core.annotation.FillField;
import com.leenmvc.core.base.BaseEntity;
import com.leenmvc.core.cache.CacheFactory;
import com.leenmvc.core.dao.mysql.wrapper.CountWrapper;
import com.leenmvc.core.dao.mysql.wrapper.DeleteWrapper;
import com.leenmvc.core.dao.mysql.wrapper.QueryWrapper;
import com.leenmvc.core.dao.mysql.wrapper.UpdateWrapper;
import com.leenmvc.core.enums.EntityInfoEnum;
import com.leenmvc.core.enums.SqlType;
import com.leenmvc.core.exception.DaoException;
import com.leenmvc.core.init.Constant;
import com.leenmvc.core.security.User;
import com.leenmvc.core.security.entity.core.SysLogSql;
import com.leenmvc.core.utils.ClassUtil;
import com.leenmvc.core.utils.StringUtils;
import com.leenmvc.core.utils.TipUtil;
import com.leenmvc.core.utils.collection.ArrayUtils;
import com.leenmvc.core.utils.logger.LogEntityPool;
import com.leenmvc.core.utils.thread.ThreadLocalManager;
import com.leenmvc.core.utils.thread.runnables.LogToDb;
import com.mysql.cj.jdbc.exceptions.MysqlDataTruncation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.Date;
import java.util.*;

/**
 * 持久层公用方法
 * 定义规则： find开头的方法查询出来的结果将不含有任何关联表的字段
 * get开头的方法查询出来的结果将含有单字段关联的字段
 * search开头的方法查询出来的结果将含有一对一
 * look开头的方法将查询出来的结果将含有一对多
 * gsRecords开头的方法将含有单字段和一对一的记录
 * glRecords开头的方法将含有单字段和一对多的记录
 * gslRecords开头的方法将含有单字段、一对一和一对多的记录
 * slRecords开头的方法将含有一对一和一对多的记录
 */
public abstract class CommonDao {

    private final static Logger logger = LoggerFactory.getLogger(CommonDao.class);

    protected WrapperFactory getWrapperFactory(Class<?> cls) {
        return BaseEntity.getDialect(cls).getWrapperFactory();
    }

    private ConnectionFactory getConnectionFactory(Class<?> cls) {
        return BaseEntity.getDialect(cls).getConnectionFactory();
    }

    private Connection getConnection(Wrapper wrapper) {
        return getConnectionFactory(wrapper.getCls()).getConnection(wrapper, wrapper.getCls());
    }

    private Connection getConnection(Class<?> cls, String sql) {
        return getConnectionFactory(cls).getConnection(sql, cls);
    }

    private Connection getConnection(Class<?> cls, StringBuilder sql) {
        return getConnectionFactory(cls).getConnection(sql.toString(), cls);
    }

    /**
     * 根据sql语句获取实体列表
     *
     * @param cls 结果集封装成哪个实体
     * @param sql 执行的sql语句
     * @param <T>
     * @return
     */
    protected <T> List<T> getListBySql(Class<?> cls, StringBuilder sql) {
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        List<T> list = new ArrayList<T>();
        Connection connection = null;
        try {
            connection = getConnection(cls, sql);
            preparedStatement = connection.prepareStatement(sql.toString());
            resultSet = executeQuery(preparedStatement, sql.toString());
            Field[] fillFieldMultiples = BaseEntity.getFillFieldByType(cls, EntityInfoEnum.FILL_FIELD_ONE_TO_MULTIPLE);
            if (fillFieldMultiples.length == 0) { // 有过没有1对3的联查那么
                buildEntityListSimple(cls, resultSet, list);
            } else {
                buildEntityListForMuti(cls, resultSet, list, fillFieldMultiples);
            }
            return list;
        } catch (SQLException e) {
            logger.error(e.getMessage(), e);
        } finally {
            getConnectionFactory(cls).close(resultSet, preparedStatement, connection);
        }
        return null;
    }

    /**
     * 根据ID删除(只适合有一个主键的方法）
     *
     * @param id
     * @param cls
     */
    public boolean deleteById(Class<?> cls, Object id) {
        DeleteWrapper deleteWrapper = getWrapperFactory(cls).getDeleteWrapper(cls);
        deleteWrapper.eq(BaseEntity.getPrimaryFieldName(cls), id);
        int num = delByWrapper(deleteWrapper);
        return num == 1;
    }

    /**
     * 根据字段，字段值键值对删除
     *
     * @param cls
     * @param kvs
     * @return
     */
    public int delete(Class<?> cls, Object... kvs) {
        DeleteWrapper deleteWrapper = getWrapperFactory(cls).getDeleteWrapper(cls);
        for(int i = 0; i < kvs.length; i+=2) {
            deleteWrapper.eq(String.valueOf(kvs[i]), kvs[i+1]);
        }
        int num = delByWrapper(deleteWrapper);
        return num;
    }

    /**
     * 根据IDs批量删除
     *
     * @param cls
     * @param ids
     */
    public int deleteByIds(Class<?> cls, Object[] ids) {
        DeleteWrapper deleteWrapper = getWrapperFactory(cls).getDeleteWrapper(cls);
        deleteWrapper.in(BaseEntity.getPrimaryFieldName(cls), ids);
        return delByWrapper(deleteWrapper);
    }

    /**
     * 根据map更新数据
     *
     * @param cls
     * @param <T>
     */
    public <T> int update(Class<?> cls, Map<String, Object> params) {
        UpdateWrapper updateWrapper = getWrapperFactory(cls).getUpdateWrapper(cls);
        for(String param: params.keySet()) {
            updateWrapper.addSet(param, params.get(param));
        }
        updateWrapper.eq(BaseEntity.getPrimaryFieldName(cls), params.get(BaseEntity.getPrimaryFieldName(cls)));
        return updateByWrapper(updateWrapper);
    }

    /**
     * 必须是成对的键值对（默认只支持一个主键）
     *
     * @param id  修改ID
     * @param kv  键值对
     * @param <T>
     */
    public <T> boolean update(Class<?> cls, Object id, Object... kv) {
        UpdateWrapper updateWrapper = getWrapperFactory(cls).getUpdateWrapper(cls);
        for(int i = 0; i < kv.length; i+=2) {
            updateWrapper.addSet(String.valueOf(kv[i]), kv[i+1]);
        }
        updateWrapper.eq(BaseEntity.getPrimaryFieldName(cls), id);
        int num = updateByWrapper(updateWrapper);
        return num == 1;
    }

    /**
     * 更新方法
     *
     * @param t
     * @param <T>
     */

    public <T> boolean update(T t) {
        UpdateWrapper updateWrapper = getWrapperFactory(t.getClass()).getUpdateWrapper(t);
        int num = updateByWrapper(updateWrapper);
        return num == 1;

    }

    /**
     * 移除
     *
     * @param t
     * @param <T>
     */

    public <T> boolean remove(T t) {
        Class<?> cls = t.getClass();
        DeleteWrapper deleteWrapper = getWrapperFactory(cls).getDeleteWrapper(cls);
        deleteWrapper.eq(BaseEntity.getPrimaryColumnName(cls), ClassUtil.getPrimaryFieldValue(t));
        int num = delByWrapper(deleteWrapper);
        return num == 1;
    }

    /**
     * @param list 批量删除
     * @param <T>
     * @return
     */

    public <T> int batchRemove(List<T> list) {
        Object[] sqlParams = new Object[0];
        Class<?> cls = null;
        for (T t : list) {
            if(cls == null) cls = t.getClass();
            String id = ClassUtil.getPrimaryFieldValue(t);
            ArrayUtils.arrayAdd(sqlParams, id);
        }
        return deleteByIds(cls, sqlParams);

    }

    /**
     * 根据Wrapper获取单条记录
     *
     * @param queryWrapper
     * @param <T>
     * @return
     */
    public <T> T get(Wrapper queryWrapper) {
        Object[] sqlParams = new Object[0];
        List<Object> paramList = queryWrapper.getParamList();
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        Connection connection = getConnection(queryWrapper);
        String sql = queryWrapper.getSql();
        try {
            preparedStatement = connection.prepareStatement(sql);
            int num = 1;
            for (Object obj : paramList) {
                preparedStatement.setObject(num, obj);
                sqlParams = ArrayUtils.arrayAdd(sqlParams, obj);
                num++;
            }
            resultSet = executeQuery(preparedStatement, sql, sqlParams);

            while (resultSet.next()) {
                Object object = buildSingleEntity(queryWrapper, resultSet);
                if (!resultSet.next()) {
                    return (T) object;
                }
                throw new DaoException("有多条满足条件的记录，与接收句柄冲突！");
            }
        } catch (SQLException e) {
            logger.error(e.getMessage(), e);
        } finally {
            getConnectionFactory(queryWrapper.getCls()).close(resultSet, preparedStatement, connection);
            getWrapperFactory(queryWrapper.getCls()).closeWrapper(queryWrapper);
        }
        return null;
    }


    /**
     * 根据 ID 获取
     *
     * @param id  ID
     * @param cls 类
     * @param <T>
     * @return
     */

    public <T> T get(Class<?> cls, Object id) {
        Wrapper wrapper = getWrapperFactory(cls).getQueryWrapper(cls);
        wrapper.eq(BaseEntity.getPrimaryFieldName(cls), id);
        return get(wrapper);
    }

    /**
     * 根据传入的键值对获取一个记录
     *
     * @param cls
     * @param kvs
     * @param <T>
     * @return
     */

    public <T> T get(Class<?> cls, Object... kvs) {
        Wrapper wrapper = getWrapperFactory(cls).getQueryWrapper(cls);
        for (int i = 0; i < kvs.length; i += 2) {
            wrapper.eq(String.valueOf(kvs[i]), kvs[i + 1]);
        }
        return get(wrapper);
    }

    /**
     * 根据传入的键值对获取一个记录
     *
     * @param cls
     * @param kvs
     * @param <T>
     * @return
     */

    public <T> List<T> getList(Class<?> cls, Object... kvs) {
        Wrapper wrapper = getWrapperFactory(cls).getQueryWrapper(cls);
        for (int i = 0; i < kvs.length; i += 2) {
            wrapper.eq(String.valueOf(kvs[i]), kvs[i + 1]);
        }
        return query(wrapper);
    }

    /**
     * 根据sql语句获取map对象
     *
     * @param queryWrapper
     * @return
     */
    public Map<String, Object> getMap(Wrapper queryWrapper) {
        Object[] sqlParams = new Object[0];
        List<Object> paramList = queryWrapper.getParamList();
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        Connection connection = getConnection(queryWrapper);
        String sql = queryWrapper.getSql();
        try {
            preparedStatement = connection.prepareStatement(sql);
            int num = 1;
            for (Object obj : paramList) {
                preparedStatement.setObject(num, obj);
                sqlParams = ArrayUtils.arrayAdd(sqlParams, obj);
                num++;
            }
            resultSet = executeQuery(preparedStatement, sql, sqlParams);
            ResultSetMetaData rsmd = resultSet.getMetaData();
            int columnCount = resultSet.getMetaData().getColumnCount();
            Map<String, Object> result = new HashMap<String, Object>();
            while (resultSet.next()) {
                for (int column = 1; column <= columnCount; column++) {
                    String name = rsmd.getColumnName(column);
                    result.put(BaseEntity.humpLine(name), resultSet.getObject(name));
                }
                if (resultSet.next()) {
                    throw new DaoException("有多条满足条件的记录，与接收句柄冲突！");
                }
            }
            return result;
        } catch (SQLException e) {
            logger.error(e.getMessage(), e);
        } finally {
            getConnectionFactory(queryWrapper.getCls()).close(resultSet, preparedStatement, connection);
            getWrapperFactory(queryWrapper.getCls()).closeWrapper(queryWrapper);
        }
        return null;
    }

    ;

    /**
     * 获取 一个Map列表
     *
     * @param queryWrapper
     * @return
     */
    public List<Map<String, Object>> getListMap(Wrapper queryWrapper) {
        Object[] sqlParams = new Object[0];
        List<Object> paramList = queryWrapper.getParamList();
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        List<Map<String, Object>> list = new ArrayList<>();
        Connection connection = getConnection(queryWrapper);
        String sql = queryWrapper.getSql();
        try {
            preparedStatement = connection.prepareStatement(sql);
            int num = 1;
            for (Object obj : paramList) {
                preparedStatement.setObject(num, obj);
                sqlParams = ArrayUtils.arrayAdd(sqlParams, obj);
                num++;
            }
            resultSet = executeQuery(preparedStatement, sql, sqlParams);
            ResultSetMetaData rsmd = resultSet.getMetaData();
            int columnCount = resultSet.getMetaData().getColumnCount();
            Map<String, Object> result = null;
            while (resultSet.next()) {
                result = new HashMap<>();
                for (int column = 1; column <= columnCount; column++) {
                    String name = rsmd.getColumnLabel(column);
                    result.put(BaseEntity.humpLine(name.toLowerCase()), resultSet.getObject(name));
                }
                list.add(result);
            }
            return list;
        } catch (SQLException e) {
            logger.error(e.getMessage(), e);
        } finally {
            getConnectionFactory(queryWrapper.getCls()).close(resultSet, preparedStatement, connection);
            getWrapperFactory(queryWrapper.getCls()).closeWrapper(queryWrapper);
        }
        return null;
    }

    public int delByWrapper(Wrapper queryWrapper) {
        Object[] sqlParams = new Object[0];
        List<Object> paramList = queryWrapper.getParamList();
        PreparedStatement preparedStatement = null;
        String sql = queryWrapper.getSql();
        Connection connection = getConnection(queryWrapper);
        try {
            preparedStatement = connection.prepareStatement(sql);
            int num = 1;
            for (Object obj : paramList) {
                preparedStatement.setObject(num, obj);
                sqlParams = ArrayUtils.arrayAdd(sqlParams, obj);
                num++;
            }
            return executeUpdate(preparedStatement, sql, sqlParams);
        } catch (SQLException e) {
            logger.error(e.getMessage(), e);
        } finally {
            getConnectionFactory(queryWrapper.getCls()).close(null, preparedStatement, connection, SqlType.DELETE);
            getWrapperFactory(queryWrapper.getCls()).closeWrapper(queryWrapper);
        }
        return 0;
    }

    public int updateByWrapper(Wrapper queryWrapper) {
        Object[] sqlParams = new Object[0];
        if (queryWrapper.getWhere().length() == 0) {
            throw new DaoException("危险更新操作， 没有条件的更新！！");
        }
        List<Object> paramList = queryWrapper.getParamList();
        PreparedStatement preparedStatement = null;
        Connection connection = getConnection(queryWrapper);
        String sql = queryWrapper.getSql();
        try {
            preparedStatement = connection.prepareStatement(sql);
            int num = 1;
            for (Object obj : paramList) {
                preparedStatement.setObject(num, obj);
                sqlParams = ArrayUtils.arrayAdd(sqlParams, obj);
                num++;
            }
            return executeUpdate(preparedStatement, sql, sqlParams);
        } catch (SQLException e) {
            logger.error(e.getMessage(), e);
        } finally {
            getConnectionFactory(queryWrapper.getCls()).close(null, preparedStatement, connection, SqlType.UPDATE);
            getWrapperFactory(queryWrapper.getCls()).closeWrapper(queryWrapper);
        }
        return 0;
    }

    public <T> List<T> oneFieldList(Wrapper queryWrapper) {
        Object[] sqlParams = new Object[0];
        List<T> result = new ArrayList<>();
        List<Object> paramList = queryWrapper.getParamList();
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        Connection connection = getConnection(queryWrapper);
        String sql = queryWrapper.getSql();
        try {
            preparedStatement = connection.prepareStatement(sql);
            int num = 1;
            for (Object obj : paramList) {
                preparedStatement.setObject(num, obj);
                sqlParams = ArrayUtils.arrayAdd(sqlParams, obj);
                num++;
            }
            resultSet = executeQuery(preparedStatement, sql, sqlParams);
            while (resultSet.next()) {
                result.add((T) resultSet.getObject(queryWrapper.getColumns().get(0)));
            }
            return result;
        } catch (SQLException e) {
            logger.error(e.getMessage(), e);
        } finally {
            getConnectionFactory(queryWrapper.getCls()).close(resultSet, preparedStatement, connection);
            getWrapperFactory(queryWrapper.getCls()).closeWrapper(queryWrapper);
        }
        return null;
    }


    /**
     * 根据条件分页获取指定类型的实体列表
     *
     * @param cls
     * @param conditions
     * @param pageInfo
     * @param <T>
     * @return
     */
    public <T> List<T> getPageList(Class<?> cls, Map<String, Object> conditions, Integer... pageInfo) {
        Wrapper wrapper = getWrapperFactory(cls).getQueryWrapper(cls);
        wrapper.mapToWrapper(conditions).limit(pageInfo);
        return getPageList(wrapper);
    }

    /**
     * 分页获取记录
     *
     * @return
     */
    public <T> List<T> getPageList(Class<?> cls, Integer... pageInfo) {
        Wrapper wrapper = getWrapperFactory(cls).getQueryWrapper(cls);
        wrapper.limit(pageInfo);
        return getPageList(wrapper);
    }

    /**
     * 获取一个值
     *
     * @param queryWrapper
     * @param <T>
     * @return
     */
    public <T> T getOneField(Wrapper queryWrapper) {
        Object[] sqlParams = new Object[0];
        List<Object> paramList = queryWrapper.getParamList();
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        Connection connection = getConnection(queryWrapper);
        String sql = queryWrapper.getSql();
        try {
            preparedStatement = connection.prepareStatement(sql);
            int num = 1;
            for (Object obj : paramList) {
                preparedStatement.setObject(num, obj);
                sqlParams = ArrayUtils.arrayAdd(sqlParams, obj);
                num++;
            }
            resultSet = executeQuery(preparedStatement, sql, sqlParams);
            while (resultSet.next()) {
                Object object1 = resultSet.getObject(1);
                return (T) object1;
            }
        } catch (SQLException e) {
            logger.error(e.getMessage(), e);
        } finally {
            getConnectionFactory(queryWrapper.getCls()).close(resultSet, preparedStatement, connection);
            getWrapperFactory(queryWrapper.getCls()).closeWrapper(queryWrapper);
        }
        return null;
    }

    /**
     * 根据包装类获取列表
     *
     * @param queryWrapper
     * @param <T>
     * @return
     */
    public <T> List<T> query(Wrapper queryWrapper) {
        Object[] sqlParams = new Object[0];
        List<Object> paramList = queryWrapper.getParamList();
        List<T> list = new ArrayList<T>();
        PreparedStatement preparedStatement = null;
        Connection connection = getConnection(queryWrapper);
        ResultSet resultSet = null;
        String sql = queryWrapper.getSql();
        try {
            preparedStatement = connection.prepareStatement(sql);
            int num = 1;
            for (Object obj : paramList) {
                preparedStatement.setObject(num, obj);
                sqlParams = ArrayUtils.arrayAdd(sqlParams, obj);
                num++;
            }
            resultSet = executeQuery(preparedStatement, sql, sqlParams);
            Field[] fillFieldMultiples = queryWrapper.getOneToMulFields();
            if (fillFieldMultiples.length == 0) { // 有过没有1对3的联查那么
                buildEntityListSimple(queryWrapper, resultSet, list);
            } else {
                buildEntityListForMuti(queryWrapper, resultSet, list, fillFieldMultiples);
            }
            return list;
        } catch (SQLException e) {
            logger.error(e.getMessage(), e);
        } finally {
            getConnectionFactory(queryWrapper.getCls()).close(resultSet, preparedStatement, connection);
            getWrapperFactory(queryWrapper.getCls()).closeWrapper(queryWrapper);
        }
        return null;
    }

    /**
     * 根据传入的Ma获取一个记录
     *
     * @param cls
     * @param <T>
     * @return
     */

    public <T> List<T> getList(Class<?> cls, Map<String, Object> params) {
        QueryWrapper wrapper = getWrapperFactory(cls).getQueryWrapper(cls);
        wrapper.mapToWrapper(params);
        return query(wrapper);
    }

    /**
     * 根据动态拼接的sql语句返回结果
     *
     * @param queryWrapper
     * @param <T>
     * @return
     */
    public <T> List<T> getPageList(Wrapper queryWrapper) {
        Object[] sqlParams = new Object[0];
        List<Object> paramList = queryWrapper.getParamList();
        List<T> list = new ArrayList<T>();
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        Class<?> cls = queryWrapper.getCls();
        Connection connection = getConnection(queryWrapper);
        String sql = queryWrapper.getSql();
        try {
            preparedStatement = connection.prepareStatement(sql);
            int num = 1;
            for (Object obj : paramList) {
                preparedStatement.setObject(num, obj);
                sqlParams = ArrayUtils.arrayAdd(sqlParams, obj);
                num++;
            }
            resultSet = executeQuery(preparedStatement, sql, sqlParams);
            Field[] fillFieldMultiples = queryWrapper.getOneToMulFields();
            if (fillFieldMultiples.length == 0) { // 有过没有1对3的联查那么
                buildEntityListSimple(queryWrapper, resultSet, list);
            } else {
                buildEntityListForMuti(queryWrapper, resultSet, list, fillFieldMultiples);
            }

            return list;
        } catch (SQLException e) {
            logger.error(e.getMessage(), e);
        } finally {
            getConnectionFactory(cls).close(resultSet, preparedStatement, connection);
            getWrapperFactory(cls).closeWrapper(queryWrapper);
        }
        return null;
    }

    /**
     * 根据 条件 获取一个实体
     *
     * @param cls
     * @param params
     * @param <T>
     * @return
     */

    public <T> T get(Class<?> cls, Map<String, Object> params) {
        Wrapper wrapper = getWrapperFactory(cls).getQueryWrapper(cls);
        wrapper.mapToWrapper(params);
        return get(wrapper);
    }

    /**
     * 获取全部数据
     *
     * @param cls
     * @param <T>
     * @return
     */

    public <T> List<T> getAll(Class<?> cls) {
        Wrapper wrapper = getWrapperFactory(cls).getQueryWrapper(cls);
        return query(wrapper);
    }

    /**
     * @param cls
     * @param sql
     * @param objects
     * @param <T>
     * @return
     */

    public <T> List<T> query(Class<?> cls, String sql, Object... objects) {
        Object[] sqlParams = new Object[0];
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        List<T> list = new ArrayList<T>();
        Connection connection = getConnection(cls, sql);
        try {
            preparedStatement = connection.prepareStatement(sql);
            for (int i = 1; i < objects.length + 1; i++) {
                preparedStatement.setObject(i, objects[i - 1]);
                sqlParams = ArrayUtils.arrayAdd(sqlParams, objects[i - 1]);
            }
            resultSet = executeQuery(preparedStatement, sql, sqlParams);
            buildEntityListSimple(cls, resultSet, list);
            return list;
        } catch (SQLException e) {
            logger.error(e.getMessage(), e);
        } finally {
            getConnectionFactory(cls).close(resultSet, preparedStatement, connection);
        }
        return null;
    }

    /**
     * 根据sql语句获取map对象
     *
     * @param sql
     * @param objects
     * @return
     */
    public Map<String, Object> getMap(Class<?> cls, String sql, Object... objects) {
        Object[] sqlParams = new Object[0];
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        Connection connection = getConnection(cls, sql);
        try {
            preparedStatement = connection.prepareStatement(sql);
            for (int i = 1; i < objects.length + 1; i++) {
                preparedStatement.setObject(i, objects[i - 1]);
                sqlParams = ArrayUtils.arrayAdd(sqlParams, objects[i - 1]);
            }
            resultSet = executeQuery(preparedStatement, sql, sqlParams);
            ResultSetMetaData rsmd = resultSet.getMetaData();
            int columnCount = resultSet.getMetaData().getColumnCount();
            Map<String, Object> result = new HashMap<>();
            while (resultSet.next()) {
                for (int column = 1; column <= columnCount; column++) {
                    String name = rsmd.getColumnName(column);
                    result.put(BaseEntity.humpLine(name), resultSet.getObject(name));
                }
            }
            return result;
        } catch (SQLException e) {
            logger.error(e.getMessage(), e);
        } finally {
            getConnectionFactory(cls).close(resultSet, preparedStatement, connection);
        }
        return null;
    }

    /**
     * 传入sql 传递参数获取一个列表
     *
     * @param sql
     * @param objects
     * @return
     */
    public List<Map<String, Object>> getListMap(Class<?> cls, String sql, Object... objects) {
        Object[] sqlParams = new Object[0];
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        List<Map<String, Object>> list = new ArrayList<>();
        Connection connection = getConnectionFactory(cls).getConnection(sql, cls);
        try {
            preparedStatement = connection.prepareStatement(sql);
            for (int i = 1; i < objects.length + 1; i++) {
                preparedStatement.setObject(i, objects[i - 1]);
                sqlParams = ArrayUtils.arrayAdd(sqlParams, objects[i - 1]);
            }
            resultSet = executeQuery(preparedStatement, sql, sqlParams);
            ResultSetMetaData rsmd = resultSet.getMetaData();
            int columnCount = resultSet.getMetaData().getColumnCount();
            Map<String, Object> result = null;
            while (resultSet.next()) {
                result = new HashMap<>();
                for (int column = 1; column <= columnCount; column++) {
                    String name = rsmd.getColumnName(column);
                    result.put(BaseEntity.humpLine(name), resultSet.getObject(name));
                }
                list.add(result);
            }
            return list;
        } catch (SQLException e) {
            logger.error(e.getMessage(), e);
        } finally {
            getConnectionFactory(cls).close(resultSet, preparedStatement, connection);
        }
        return null;
    }

    /**
     * 保存
     *
     * @param t
     * @param <T>
     */
    public <T> boolean insert(T t) {
        Object[] sqlParams = new Object[0];
        Class<?> cls = t.getClass();
        List<String> columns = new ArrayList<String>();
        StringBuilder sql = new StringBuilder("insert into ").append(BaseEntity.getTableName(cls)).append("(");
        // 绘制sql语句
        Field[] fields = BaseEntity.getDBFields(cls);
        for (Field field : fields) {
            columns.add(BaseEntity.humpLine(field.getName()));
        }
        sql.append(StringUtils.join(columns, Constant.COMMA)).append(")").append(" values (");
        columns.clear();
        for (int i = 0; i < fields.length; i++) {
            columns.add(Constant.QUESTION_MARK_SIGN);
        }
        sql.append(StringUtils.join(columns, Constant.COMMA)).append(")");

        // 插入数据
        PreparedStatement preparedStatement = null;
        Connection connection = getConnection(cls, sql);
        try {
            preparedStatement = connection.prepareStatement(sql.toString());
            for (int i = 1; i < fields.length + 1; i++) {
                Object fieldValue = ClassUtil.getFieldValue(t, fields[i - 1].getName());
                preparedStatement.setObject(i, fieldValue);
                sqlParams = ArrayUtils.arrayAdd(sqlParams, fieldValue);
            }
            return executeUpdate(preparedStatement, sql, sqlParams) == 1;
        } catch (SQLException e) {
            logger.error(e.getMessage(), e);
        } finally {
            getConnectionFactory(cls).close(null, preparedStatement, connection, SqlType.INSERT);
        }
        return false;
    }


    public <T> boolean insert(Class<?> cls, Map<String, Object> entityMap) {
        T t = ClassUtil.mapToEntity(cls, entityMap);
        return insert(t);
    }

    /**
     * 批量插入
     *
     * @param insertList
     * @param <T>
     */
    public <T> boolean batchInsert(List<T> insertList) {
        Object[] sqlParams = new Object[0];
        T t = null;
        if (insertList.size() <= 0) {
            logger.error("执行批量插入时列表为空！插入失败！");
            return false;
        }
        t = insertList.get(0);
        Class<?> cls = t.getClass();

        List<String> columns = new ArrayList<String>();
        StringBuilder sql = new StringBuilder("insert into ").append(BaseEntity.getTableName(cls)).append("(");
        // 绘制sql语句
        Field[] fields = cls.getDeclaredFields();
        for (Field field : fields) {
            columns.add(BaseEntity.humpLine(field.getName()));
        }
        sql.append(StringUtils.join(columns, Constant.COMMA)).append(") values ");
        List<String> value = new ArrayList<String>();
        for (int i = 0; i < insertList.size(); i++) {
            StringBuilder temp = new StringBuilder("(");
            List<String> qList = new ArrayList<String>();
            for (Field field : fields) {
                qList.add(Constant.QUESTION_MARK_SIGN);
            }
            temp.append(StringUtils.join(qList, Constant.COMMA)).append(")");
            value.add(temp.toString());
        }
        sql.append(StringUtils.join(value, Constant.COMMA));

        // 插入数据
        PreparedStatement preparedStatement = null;
        Connection connection = getConnection(cls, sql);
        try {
            preparedStatement = connection.prepareStatement(sql.toString());
            for (int j = 0; j < insertList.size(); j++) {
                for (int i = 1; i < fields.length + 1; i++) {
                    Object fieldValue = ClassUtil.getFieldValue(insertList.get(j), fields[i - 1].getName());
                    preparedStatement.setObject(i + j * fields.length, fieldValue);
                    sqlParams = ArrayUtils.arrayAdd(sqlParams, fieldValue);
                }
            }
            int num = executeUpdate(preparedStatement, sql, sqlParams);
            return num > 0;
        } catch (SQLException e) {
            logger.error(e.getMessage(), e);
        } finally {
            getConnectionFactory(cls).close(null, preparedStatement, connection, SqlType.INSERT);
        }
        return false;
    }

    public <T> boolean saveOrUpdate(T t) {
        Class<?> cls = t.getClass();
        Method primaryGetMethod = ClassUtil.getPrimaryGetMethod(cls);
        Object id = null;

        try {
            id = primaryGetMethod.invoke(t, null);
            Object o = get(cls, id);
            if (o == null) {
                return insert(t);
            } else {
                return update(t);
            }
        } catch (IllegalAccessException e) {
            logger.error(e.getMessage(), e);
        } catch (InvocationTargetException e) {
            logger.error(e.getMessage(), e);
        }
        return false;
    }

    /**
     * 批量插入
     *
     * @param ts
     * @param <T>
     */
    public <T> boolean batchInsert(T[] ts) {
        Object[] sqlParams = new Object[0];
        T t = null;
        if (ts.length <= 0) {
            logger.error("列表数量为空！执行批量插入失败！");
            return false;
        }
        t = ts[0];
        Class<?> cls = t.getClass();
        List<String> columns = new ArrayList<String>();
        StringBuilder sql = new StringBuilder("insert into ").append(BaseEntity.getTableName(cls)).append("(");
        // 绘制sql语句
        Field[] fields = cls.getDeclaredFields();
        for (Field field : fields) {
            columns.add(BaseEntity.humpLine(field.getName()));
        }
        sql.append(StringUtils.join(columns, Constant.COMMA)).append(") values ");
        List<String> value = new ArrayList<String>();
        for (int i = 0; i < ts.length; i++) {
            StringBuilder temp = new StringBuilder("(");
            List<String> qList = new ArrayList<String>();
            for (Field field : fields) {
                qList.add(Constant.QUESTION_MARK_SIGN);
            }
            temp.append(StringUtils.join(qList, Constant.COMMA)).append(")");
            value.add(temp.toString());
        }
        sql.append(StringUtils.join(value, Constant.COMMA));

        // 插入数据
        PreparedStatement preparedStatement = null;
        Connection connection = getConnection(cls, sql);
        try {
            preparedStatement = connection.prepareStatement(sql.toString());
            for (int j = 0; j < ts.length; j++) {
                for (int i = 1; i < fields.length + 1; i++) {
                    Object fieldValue = ClassUtil.getFieldValue(ts[j], fields[i - 1].getName());
                    preparedStatement.setObject(i + j * fields.length, fieldValue);
                    sqlParams = ArrayUtils.arrayAdd(sqlParams, fieldValue);
                }
            }
            preparedStatement.execute();
        } catch (SQLException e) {
            logger.error(e.getMessage(), e);
        } finally {
            getConnectionFactory(cls).close(null, preparedStatement, connection, SqlType.INSERT);
        }
        return false;
    }

    /**
     * 根据条件获取数量
     *
     * @param cls
     * @param params
     * @return
     */
    public int count(Class<?> cls, Map<String, Object> params) {
        CountWrapper countWrapper = getWrapperFactory(cls).getCountWrapper(cls);
        for(String param: params.keySet()) {
            countWrapper.eq(param, params.get(param));
        }
        return count(countWrapper);
    }

    /**
     * 键值对形式传参
     *
     * @param cls
     * @param kvs
     * @return
     */
    public int count(Class<?> cls, Object... kvs) {
        CountWrapper countWrapper = getWrapperFactory(cls).getCountWrapper(cls);
        for(int i = 0; i < kvs.length; i+=2) {
            countWrapper.eq(String.valueOf(kvs[i]), kvs[i + 1]);
        }
        return count(countWrapper);
    }

    /**
     * 根据包装类获取数量
     *
     * @param queryWrapper
     * @return
     */
    public int count(Wrapper queryWrapper) {
        Object[] sqlParams = new Object[0];
        List<Object> paramList = queryWrapper.getParamList();
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        Connection connection = getConnection(queryWrapper);
        String sql = queryWrapper.getSql();
        try {
            preparedStatement = connection.prepareStatement(sql);
            int num = 1;
            for (Object obj : paramList) {
                preparedStatement.setObject(num, obj);
                sqlParams = ArrayUtils.arrayAdd(sqlParams, obj);
                num++;
            }
            resultSet = executeQuery(preparedStatement, sql, sqlParams);
            while (resultSet.next()) {
                return resultSet.getInt(1);
            }
        } catch (SQLException e) {
            logger.error(e.getMessage(), e);
        } finally {
            getConnectionFactory(queryWrapper.getCls()).close(resultSet, preparedStatement, connection);
            BaseEntity.getDialect(queryWrapper.getCls()).getWrapperFactory().closeWrapper(queryWrapper);
        }
        return 0;
    }

    /**
     * 查询某个数据表记录条数
     *
     * @param cls
     * @return
     */
    public int count(Class<?> cls) {
        CountWrapper countWrapper = getWrapperFactory(cls).getCountWrapper(cls);
        return count(countWrapper);
    }

    protected void addWhereCondition(Map<String, Object> conditions, StringBuilder sql) {
        if (conditions.size() == 0) return;
        // 添加查询条件
        List<String> wheres = new ArrayList<String>();
        for (String key : conditions.keySet()) {
            wheres.add(BaseEntity.humpLine(key) + " = ? ");
        }
        if (wheres.size() > 0) {
            sql.append(Constant.BLANK_AND).append(StringUtils.join(wheres, Constant.BLANK_AND));
        }
    }


    protected ResultSet executeQuery(PreparedStatement preparedStatement, String sql) {
        try {
            return executeQuery(preparedStatement, sql, null);
        } catch (SQLException e) {
            logger.error(e.getMessage(), e);
        }
        return null;
    }

    protected ResultSet executeQuery(PreparedStatement preparedStatement, StringBuilder sql, Object[] params) {
        try {
            return executeQuery(preparedStatement, sql.toString(), params);
        } catch (SQLException e) {
            logger.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 最后执行查询的方法
     * 在此方法进行日志的记录
     *
     * @param preparedStatement
     * @param sql
     * @param params
     * @return
     * @throws SQLException
     */
    protected ResultSet executeQuery(PreparedStatement preparedStatement, String sql, Object[] params) throws SQLException {
        long start = System.currentTimeMillis();
        logger.info("执行了一个SQL查询：{}", sql);
        logger.info("SQL查询的参数是：{}", Arrays.toString(params));
        ResultSet resultSet = preparedStatement.executeQuery();
        if (ThreadLocalManager.isLog() == 0 && CacheFactory.getStatus("SAVE_QUERYSQL_LOG")) {
            SysLogSql logSql = LogEntityPool.getLogSql();
            logSql.setSqlStr(sql);
            logSql.setParams(Arrays.toString(params));
            logSql.setUsername(User.getUsername());
            logSql.setExcuteTime((int) (System.currentTimeMillis() - start));
            logSql.setCreateDate(new Date());
            logSql.setInfluence(0);
            logSql.setNote(String.valueOf(ThreadLocalManager.get(Constant.CONTROLLER_NOTE)));
            logSql.setUri(String.valueOf(ThreadLocalManager.get(Constant.CONTROLLER_URI)));
            LogToDb.addSqllog(logSql);
        }
        return resultSet;
    }

    /**
     * 最后执行增删改的方法
     * 在此处进行日志的记录
     *
     * @param preparedStatement
     * @param sql
     * @param params
     * @return
     * @throws SQLException
     */
    protected int executeUpdate(PreparedStatement preparedStatement, String sql, Object[] params) throws MysqlDataTruncation {
        Long start = System.currentTimeMillis();
        int num = 0;
        try {
            num = preparedStatement.executeUpdate();
        } catch (MysqlDataTruncation e) {
            logger.error(e.getMessage(), e);
            String message = e.getMessage();
            String field = message.substring(message.indexOf("'") + 1, message.lastIndexOf("'"));
            throw new DaoException(TipUtil.getTip("FIELD_TOO_LANG", field), true);
        } catch (SQLException e) {
            logger.error(e.getMessage(), e);
        }
        logger.info("执行了一个SQL增删改操作：{}", sql);
        logger.info("本次增删改参数为：{}", Arrays.toString(params));
        if (ThreadLocalManager.isLog() == 0 && CacheFactory.getStatus("SAVE_DDLSQL_LOG")) {
            SysLogSql logSql = LogEntityPool.getLogSql();
            logSql.setSqlStr(sql);
            logSql.setParams(Arrays.toString(params));
            logSql.setUsername(User.getUsername());
            logSql.setInfluence(num);
            logSql.setExcuteTime((int) (System.currentTimeMillis() - start));
            logSql.setCreateDate(new Date());
            logSql.setNote(String.valueOf(ThreadLocalManager.get(Constant.CONTROLLER_NOTE)));
            logSql.setUri(String.valueOf(ThreadLocalManager.get(Constant.CONTROLLER_URI)));
            LogToDb.addSqllog(logSql);
        }
        return num;
    }

    protected int executeUpdate(PreparedStatement preparedStatement, StringBuilder sql, Object[] params) throws SQLException {
        return executeUpdate(preparedStatement, sql.toString(), params);
    }

    protected <T> void buildEntityListSimple(Class<?> cls, ResultSet resultSet, List<T> list) {
        while (true) {
            try {
                if (!resultSet.next()) break;
                Object object = buildSingleEntity(cls, resultSet);
                list.add((T) object);
            } catch (SQLException e) {
                logger.error(e.getMessage(), e);
            }
        }
    }

    /**
     * 当结果包含一对多结果集合的时候使用这个方法
     *
     * @param cls
     * @param resultSet
     * @param list
     * @param <T>
     */
    protected <T> void buildEntityListForMuti(Class<?> cls, ResultSet resultSet, List<T> list, Field[] multi) {
        Map<Object, Object> pojoMap = new HashMap<>();
        while (true) {
            try {
                if (!resultSet.next()) break;
                String primaryFieldName = ClassUtil.getPrimaryFieldName(cls);
                Object primaryKey = resultSet.getObject(primaryFieldName);
                Object o = null;
                if (pojoMap.get(primaryKey) == null) {
                    o = buildSingleEntity(cls, resultSet);
                    for (Field field : multi) {
                        Method setMethod = ClassUtil.getSetMethod(cls, field.getName());
                        setMethod.invoke(o, new ArrayList<T>());
                    }
                    pojoMap.put(primaryKey, o);
                    list.add((T) o);
                } else {
                    o = pojoMap.get(primaryKey);
                }

                /* 如果有一对多字段的话那么就继续往下执行 */
                for (Field field : multi) {
                    Method setMethod = ClassUtil.getGetMethod(cls, field.getName());
                    List<T> invoke = (ArrayList<T>) setMethod.invoke(o);
                    Class<?> type = field.getAnnotation(FillField.class).entity();
                    logger.info("执行了一次实体联查（一对多），主表为:{}, 副表为：{}", BaseEntity.getTableName(cls), BaseEntity.getTableName(type));
                    Object o1 = type.newInstance();
                    Field[] declaredFields = type.getDeclaredFields();
                    for (Field field1 : declaredFields) {
                        if (!ClassUtil.isTableField(field1)) continue;
                        String columnName = BaseEntity.humpLine(field1.getName());
                        String columnLabel = type.getSimpleName() + columnName;
                        Object columnValue = resultSet.getObject(columnLabel);
                        Method setMethod1 = ClassUtil.getSetMethod(field1);
                        setMethod1.invoke(o1, columnValue);
                    }
                    Object primaryFieldValue = ClassUtil.getPrimaryFieldValue(o1);
                    if (primaryFieldValue != null) {
                        invoke.add((T) o1);
                    }
                }

            } catch (SQLException e) {
                logger.error(e.getMessage(), e);
            } catch (IllegalAccessException e) {
                logger.error(e.getMessage(), e);
            } catch (InvocationTargetException e) {
                logger.error(e.getMessage(), e);
            } catch (InstantiationException e) {
                logger.error(e.getMessage(), e);
            }
        }
    }

    /**
     * 当结果包含一对多结果集合的时候使用这个方法
     *
     * @param wrapper
     * @param resultSet
     * @param list
     * @param <T>
     */
    protected <T> void buildEntityListForMuti(Wrapper wrapper, ResultSet resultSet, List<T> list, Field[] multi) {
        Map<Object, Object> pojoMap = new HashMap<>();
        while (true) {
            try {
                if (!resultSet.next()) break;
                Class<?> cls = wrapper.getCls();
                String primaryFieldName = ClassUtil.getPrimaryFieldName(cls);
                Object primaryKey = resultSet.getObject(primaryFieldName);
                Object o = null;
                if (pojoMap.get(primaryKey) == null) {
                    o = buildSingleEntity(wrapper, resultSet);
                    for (Field field : multi) {
                        Method setMethod = ClassUtil.getSetMethod(cls, field.getName());
                        setMethod.invoke(o, new ArrayList<T>());
                    }
                    pojoMap.put(primaryKey, o);
                    list.add((T) o);
                } else {
                    o = pojoMap.get(primaryKey);
                }

                /* 如果有一对多字段的话那么就继续往下执行 */
                for (Field field : multi) {
                    Method setMethod = ClassUtil.getGetMethod(cls, field.getName());
                    List<T> invoke = (ArrayList<T>) setMethod.invoke(o);
                    Class<?> type = field.getAnnotation(FillField.class).entity();
                    logger.info("执行了一次实体联查（一对多），主表为:{}, 副表为：{}", BaseEntity.getTableName(cls), BaseEntity.getTableName(type));
                    Object o1 = type.newInstance();
                    Field[] declaredFields = type.getDeclaredFields();
                    for (Field field1 : declaredFields) {
                        if (!ClassUtil.isTableField(field1)) continue;
                        String columnName = BaseEntity.humpLine(field1.getName());
                        String columnLabel = type.getSimpleName() + columnName;
                        Object columnValue = resultSet.getObject(columnLabel);
                        Method setMethod1 = ClassUtil.getSetMethod(field1);
                        setMethod1.invoke(o1, columnValue);
                    }
                    Object primaryFieldValue = ClassUtil.getPrimaryFieldValue(o1);
                    if (primaryFieldValue != null) {
                        invoke.add((T) o1);
                    }
                }

            } catch (SQLException e) {
                logger.error(e.getMessage(), e);
            } catch (IllegalAccessException e) {
                logger.error(e.getMessage(), e);
            } catch (InvocationTargetException e) {
                logger.error(e.getMessage(), e);
            } catch (InstantiationException e) {
                logger.error(e.getMessage(), e);
            }
        }
    }

    protected <T> void buildEntityListSimple(Wrapper wrapper, ResultSet resultSet, List<T> list) {
        while (true) {
            try {
                if (!resultSet.next()) break;
                Object object = buildSingleEntity(wrapper, resultSet);
                list.add((T) object);
            } catch (SQLException e) {
                logger.error(e.getMessage(), e);
            }
        }
    }

    /**
     * 完整的实体循环resultSet集
     *
     * @param cls
     * @param resultSet
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws SQLException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     */
    protected Object buildSingleEntity(Class<?> cls, ResultSet resultSet) {
        Object object = null;
        try {
            object = cls.newInstance();
            Field[] declaredFields = cls.getDeclaredFields();
            for (Field field : declaredFields) {
                if (!ClassUtil.isTableField(field)) continue;
                String columnName = BaseEntity.humpLine(field.getName());
                Object columnValue = resultSet.getObject(columnName);
                Method setMethod = ClassUtil.getSetMethod(field);
                setMethod.invoke(object, columnValue);
            }
            return object;
        } catch (InstantiationException e) {
            logger.error(e.getMessage(), e);
        } catch (IllegalAccessException e) {
            logger.error(e.getMessage(), e);
        } catch (SQLException e) {
            logger.error(e.getMessage(), e);
        } catch (InvocationTargetException e) {
            logger.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 循环resultSet集
     *
     * @param queryWrapper
     * @param resultSet
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws SQLException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     */
    protected Object buildSingleEntity(Wrapper queryWrapper, ResultSet resultSet) {
        Class<?> cls = queryWrapper.getCls();
        Object object = null;
        try {
            object = cls.newInstance();
            List<String> fields = queryWrapper.getColumns();
            List<String> outFields = queryWrapper.getOutColumns();
            fields.addAll(outFields);
            for (String columnName : fields) {
                if (columnName.indexOf(Constant.DOT) != -1) {
                    columnName = columnName.split("\\.")[1];
                }
                Field field = cls.getDeclaredField(BaseEntity.humpLine(columnName));
                Object columnValue = resultSet.getObject(columnName);
                Method setMethod = ClassUtil.getSetMethod(field);
                if (columnValue == null) continue;
                try {
                    setMethod.invoke(object, columnValue);
                } catch (IllegalArgumentException e) {
                    logger.error("类型转换错误，当前转换的类是：{}, 类字段为：{};可承接的类型为:{};实际的类型为: {}", cls.getName(), columnName, field.getType(), columnValue.getClass());
                    logger.error(e.getMessage(), e);
                }
            }

            /**
             * 对FillField注解的一对一类型进行处理
             */
            Field[] oneToOneFields = queryWrapper.getOneToOneFields();
            for (Field field : oneToOneFields) {
                Class<?> fieldType = field.getType();
                logger.info("执行了一次实体联查（一对一），主表为:{}, 副表为：{}", BaseEntity.getTableName(cls), BaseEntity.getTableName(fieldType));
                Object o = fieldType.newInstance();
                Field[] dbFields = BaseEntity.getDBFields(fieldType);
                for (Field field1 : dbFields) {
                    Method setMethod = ClassUtil.getSetMethod(field1);
                    setMethod.invoke(o, resultSet.getObject(fieldType.getSimpleName() + BaseEntity.humpLine(field1)));
                }
                Method setMethod = ClassUtil.getSetMethod(field);
                setMethod.invoke(object, o);
            }

            return object;
        } catch (InstantiationException e) {
            logger.error(e.getMessage(), e);
        } catch (IllegalAccessException e) {
            logger.error(e.getMessage(), e);
        } catch (SQLException e) {
            logger.error(e.getMessage(), e);
        } catch (InvocationTargetException e) {
            logger.error(e.getMessage(), e);
        } catch (NoSuchFieldException e) {
            logger.error(e.getMessage(), e);
        }
        return null;
    }

}
